package org.tri.gui.worker;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import org.tri.gui.worker.retrievers.DataRetriever;
import org.tri.model.EntityComboBoxModel;

/**
 * La clase {@code ComboFillWorker} es un worker que se utiliza en conjunto con
 * la interfaz para realizar el rellenado del {@code EntityModel} asociado a un
 * {@code JComboBox}. 
 * @author kiira
 * @version 1.0, Jan 31, 2012
 */
public class ComboFillWorker<K> extends SwingWorker<List<K>, Object> {

    /** Modelo de entidad a rellanr. */
    private EntityComboBoxModel<K> model;
    /** Retriever que se encarga de saber COMO recuperar los datos.*/
    private DataRetriever<K> retriever;
    /** Lista de listeners del worker. */
    private List<ComboFillListener> listenerList;

    /**
     * Inicializa el filler para que trabaje con un modelo, obteniendo la info
     * del retriever.
     * @param model modelo a rellenar.
     * @param retriever retriever para obtener la data.
     */
    public ComboFillWorker( EntityComboBoxModel<K> model,
                            DataRetriever<K> retriever ) {
        super();
        this.model = model;
        this.retriever = retriever;

        listenerList = new ArrayList<ComboFillListener>();

    }//end constructor

    /**
     * Agrega un listener al worker.
     * @param listener listener a agregar.
     */
    public final void addComboFillListener( ComboFillListener listener ) {
        listenerList.add( listener );

    }//end método addTableFillListener

    /**
     * Elimina un listener del worker.
     * @param listener listener a eliminar.
     */
    public final void removeComboFillListener( ComboFillListener listener ) {
        listenerList.remove( listener );

    }//end método removeTableFillListener

    /**
     * Método utilizado para enviar el evento de finalización de la acción
     * del worker a todos los listeners registrados.
     */
    private void fireDoneFillingCombo() {
        for ( final ComboFillListener listener : listenerList )
            SwingUtilities.invokeLater( new Runnable() {

                @Override
                public void run() {
                    listener.doneFillingCombo();
                }

            } );

    }//end métdoo fireDoneFillingCombo

    /**
     * Método utilizado para enviar el evento de error a del worker a todos 
     * los listeners registrados.
     * @param ex 
     */
    private void fireErrorFillingCombo( final ExecutionException ex ) {
        for ( final ComboFillListener listener : listenerList )
            SwingUtilities.invokeLater( new Runnable() {

                @Override
                public void run() {
                    listener.errorFillingCombo( ex );
                }

            } );

    }//end método fireErrorFillingCombo

    /**
     * {@inheritDoc}
     */
    @Override
    protected List<K> doInBackground() throws Exception {
        return retriever.retrieveData();

    }//end método doInBackground

    /**
     * Setea los elementos recuperados en el combo box y envia los eventos
     * de finalizado y error(si surgiera algún error).
     */
    @Override
    protected void done() {
        super.done();

        try {
            //asignamos las filas
            model.setElementos( get() );

        } catch ( InterruptedException ex ) {
        } catch ( ExecutionException ex ) {
            //enviamos el error a los listeners
            fireErrorFillingCombo( ex );

        } finally {
            //enviamos el done a los listeners
            fireDoneFillingCombo();

        }

    }//end método done

}//end clase ComboFillWorker
